前一篇有提到 motion value 是可以搭配 useTransform
串聯多個值一起用的,可以根據一個/組數值產生一連串新的 motion value,而 useSpring
是可以針對彈簧動畫的值進行手動操作。
useTransform
是以一個 motion value 為基準,並根據 motion value 的輸入值的範圍,產生另一個 motion value,具有映射 (Mapping) 的特色。
useTransform(value, input, output, options)
value : motion value
input : value 的變化範圍,必須是線性的,正負數都可以,這樣才可以使 output 被推算出來
output : 其他別於 value 屬性的值,比如說 value 是 x ,output 可以是 opacity 等其他屬性 。作用是當 x 變化會對應到特定的 opacity 值,另外 output 也可以是數字、顏色、陰影 (shadow)。不過要注意 陣列長度要跟 input 一樣。例 : useTransform(x,[0,0,100,100],[0,1,1,0])
,input 與 output 定義的範圍陣列長度要一樣。
options : 關於轉換區間的值可以有不同的計算方式,有兩種
clamp
: 布林值 (Boolean) 。true 是預設,允許從最大、最小以及區間值做變化,超過就以兩端值為極限。false 是超過範圍的依然會計算出值給你。ease
: 緩動函式,根據 ease function 的數值變化。mixer
: (from: T, to: T) => (p: number)
。簡單來說是透過自定義的函式計算變化值。數組前後兩兩一組根據 p
的 ease 緩動值 0 到 1 來決定從 from 到 to 的混和程度。最簡單的使用 useTransform
const opacity = useTransform(
x,
// x 的範圍值
[0, 100],
// 對應 opacity 的值
[1, 0]
)
const opacity = useTransform(x,[0, 100],[1, 0],{clamp: false})
以旋轉為例 :
clamp 被取消後超過最大值還是會自己推理算出 rotate 的值
useTransform
搭配 :const x = useMotionValue(0);
const y = useMotionValue(0);
const rotateX = useTransform(y, [0, 400], [45, -45]);
const rotateY = useTransform(x, [0, 400], [-45, 45]);
除了放入一個固定的範圍值,也可以用函式來計算
export const MyComponent = () => {
const x = useMotionValue(10)
// 按照 cos 圖形上下擺動,第二個參數是 function ,其函式的參數是最新的 x 值
const y = useTransform(x, value => Math.cos(value / 10) * 50)
return <motion.div style={{ x, y }} />
}
輸入值除了一個之外,也可以使用陣列相關性的一組,透過兩個數值
export const MyComponent = () => {
const x = useMotionValue(0)
const y = useSpring(0)
const z = useTransform(
[x, y],
([latestX, latestY]) => latestX * latestY
)
return <motion.div style={{ x, y, z }} />
}
跟彈簧運動有關的值,可以接收來自別的 motion value ,也可以創造一個 motion value。
// 創造
const spring = useSpring(0)
// 使用 useMotionValue 的值
const x = useMotionValue(0)
const spring = useSpring(x)
第二個參數是一個物件,接收跟 transition type = spring
一樣的內容 :
useSpring(x, { stiffness: 1000, damping: 10 })
這樣可以控制在不同時刻的動畫數值呈現不同的動畫效果。
要注意的是操作 motion value 是副作用,相關的操作最好要在 useEffect
裡面。
const x = useSpring(0)
useEffect(() => {
x.set(target)
}, [target])
return <motion.div style={{ x }} />
可以參考 官方範例
官方的範例展示起來都好酷,也有一點難度 QQ ,最近正在收集一些動畫特效,我在想想看要怎麼搭進去範例中。明天會講到有關卷軸事件相關的 useScroll
與 useInView
。